#include <gdk/gdk.h>
#include "st-theme-node.h"
+#include <libcroco/libcroco.h>
#include "st-types.h"
G_BEGIN_DECLS
int border_radius[4];
int outline_width;
guint padding[4];
+ guint margin[4];
int width;
int height;
guint background_position_set : 1;
guint background_repeat : 1;
+ gboolean margin_set : 4;
+
guint properties_computed : 1;
guint geometry_computed : 1;
guint background_computed : 1;
void _st_theme_node_ensure_background (StThemeNode *node);
void _st_theme_node_ensure_geometry (StThemeNode *node);
+void _st_theme_node_apply_margins (StThemeNode *node,
+ ClutterActor *actor);
G_END_DECLS
}
}
+static void
+do_margin_property_term (StThemeNode *node,
+ CRTerm *term,
+ gboolean left,
+ gboolean right,
+ gboolean top,
+ gboolean bottom)
+{
+ int value;
+
+ if (get_length_from_term_int (node, term, FALSE, &value) != VALUE_FOUND)
+ return;
+
+ if (left)
+ {
+ node->margin[ST_SIDE_LEFT] = value;
+ node->margin_set |= 1 << ST_SIDE_LEFT;
+ }
+ if (right)
+ {
+ node->margin[ST_SIDE_RIGHT] = value;
+ node->margin_set |= 1 << ST_SIDE_RIGHT;
+ }
+ if (top)
+ {
+ node->margin[ST_SIDE_TOP] = value;
+ node->margin_set |= 1 << ST_SIDE_TOP;
+ }
+ if (bottom)
+ {
+ node->margin[ST_SIDE_BOTTOM] = value;
+ node->margin_set |= 1 << ST_SIDE_BOTTOM;
+ }
+}
+
+static void
+do_margin_property (StThemeNode *node,
+ CRDeclaration *decl)
+{
+ const char *property_name = decl->property->stryng->str + 6; /* Skip 'margin' */
+
+ if (strcmp (property_name, "") == 0)
+ {
+ /* Slight deviation ... if we don't understand some of the terms and understand others,
+ * then we set the ones we understand and ignore the others instead of ignoring the
+ * whole thing
+ */
+ if (decl->value == NULL) /* 0 values */
+ return;
+ else if (decl->value->next == NULL) /* 1 value */
+ {
+ do_margin_property_term (node, decl->value, TRUE, TRUE, TRUE, TRUE); /* left/right/top/bottom */
+ return;
+ }
+ else if (decl->value->next->next == NULL) /* 2 values */
+ {
+ do_margin_property_term (node, decl->value, FALSE, FALSE, TRUE, TRUE); /* top/bottom */
+ do_margin_property_term (node, decl->value->next, TRUE, TRUE, FALSE, FALSE); /* left/right */
+ }
+ else if (decl->value->next->next->next == NULL) /* 3 values */
+ {
+ do_margin_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE); /* top */
+ do_margin_property_term (node, decl->value->next, TRUE, TRUE, FALSE, FALSE); /* left/right */
+ do_margin_property_term (node, decl->value->next->next, FALSE, FALSE, FALSE, TRUE); /* bottom */
+ }
+ else if (decl->value->next->next->next->next == NULL) /* 4 values */
+ {
+ do_margin_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE); /* top */
+ do_margin_property_term (node, decl->value->next, FALSE, TRUE, FALSE, FALSE); /* right */
+ do_margin_property_term (node, decl->value->next->next, FALSE, FALSE, FALSE, TRUE); /* bottom */
+ do_margin_property_term (node, decl->value->next->next->next, TRUE, FALSE, FALSE, FALSE); /* left */
+ }
+ else
+ {
+ g_warning ("Too many values for margin property");
+ return;
+ }
+ }
+ else
+ {
+ if (decl->value == NULL || decl->value->next != NULL)
+ return;
+
+ if (strcmp (property_name, "-left") == 0)
+ do_margin_property_term (node, decl->value, TRUE, FALSE, FALSE, FALSE);
+ else if (strcmp (property_name, "-right") == 0)
+ do_margin_property_term (node, decl->value, FALSE, TRUE, FALSE, FALSE);
+ else if (strcmp (property_name, "-top") == 0)
+ do_margin_property_term (node, decl->value, FALSE, FALSE, TRUE, FALSE);
+ else if (strcmp (property_name, "-bottom") == 0)
+ do_margin_property_term (node, decl->value, FALSE, FALSE, FALSE, TRUE);
+ }
+}
+
static void
do_size_property (StThemeNode *node,
CRDeclaration *decl,
do_outline_property (node, decl);
else if (g_str_has_prefix (property_name, "padding"))
do_padding_property (node, decl);
+ else if (g_str_has_prefix (property_name, "margin"))
+ do_margin_property (node, decl);
else if (strcmp (property_name, "width") == 0)
do_size_property (node, decl, &width);
else if (strcmp (property_name, "height") == 0)
return node->padding[side];
}
+double
+st_theme_node_get_margin (StThemeNode *node,
+ StSide side)
+{
+ g_return_val_if_fail (ST_IS_THEME_NODE (node), 0.);
+ g_return_val_if_fail (side >= ST_SIDE_TOP && side <= ST_SIDE_LEFT, 0.);
+
+ _st_theme_node_ensure_geometry (node);
+
+ return node->margin[side];
+}
+
/**
* st_theme_node_get_transition_duration:
* @node: an #StThemeNode
return padding;
}
+void
+_st_theme_node_apply_margins (StThemeNode *node,
+ ClutterActor *actor)
+{
+ g_return_if_fail (ST_IS_THEME_NODE (node));
+
+ _st_theme_node_ensure_geometry (node);
+
+ // In the case that a CSS margin is not specified, we don't to set a value
+ // of 0 to the clutter actor margin. In this manner it allows to use Clutter
+ // margin values set in the code. However, the margins that are set both in
+ // the code and in the CSS on the same side, the result is unpredictable.
+ if (node->margin_set & 1 << ST_SIDE_LEFT)
+ clutter_actor_set_margin_left (actor, st_theme_node_get_margin(node, ST_SIDE_LEFT));
+ if (node->margin_set & 1 << ST_SIDE_RIGHT)
+ clutter_actor_set_margin_right (actor, st_theme_node_get_margin(node, ST_SIDE_RIGHT));
+ if (node->margin_set & 1 << ST_SIDE_TOP)
+ clutter_actor_set_margin_top (actor, st_theme_node_get_margin(node, ST_SIDE_TOP));
+ if (node->margin_set & 1 << ST_SIDE_BOTTOM)
+ clutter_actor_set_margin_bottom (actor, st_theme_node_get_margin(node, ST_SIDE_BOTTOM));
+}
+
static GetFromTermResult
parse_shadow_property (StThemeNode *node,
CRDeclaration *decl,
double st_theme_node_get_horizontal_padding (StThemeNode *node);
double st_theme_node_get_vertical_padding (StThemeNode *node);
+double st_theme_node_get_margin (StThemeNode *node,
+ StSide side);
+
int st_theme_node_get_width (StThemeNode *node);
int st_theme_node_get_height (StThemeNode *node);
int st_theme_node_get_min_width (StThemeNode *node);
#include "st-texture-cache.h"
#include "st-theme-context.h"
#include "st-theme-node-transition.h"
+#include "st-theme-node-private.h"
#include "st-widget-accessible.h"
return;
}
+ _st_theme_node_apply_margins (new_theme_node, CLUTTER_ACTOR (widget));
+
if (!old_theme_node ||
!st_theme_node_geometry_equal (old_theme_node, new_theme_node))
clutter_actor_queue_relayout ((ClutterActor *) widget);
static StThemeNode *text3;
static StThemeNode *text4;
static StThemeNode *group3;
+static StThemeNode *group4;
+static StThemeNode *group5;
+static StThemeNode *group6;
static StThemeNode *cairo_texture;
static gboolean fail;
/* 1in == 72pt == 96px, at 96dpi */
assert_length ("group1", "padding-left", 96.,
st_theme_node_get_padding (group1, ST_SIDE_LEFT));
+
+ /* 12pt == 16px at 96dpi */
+ assert_length ("group1", "margin-top", 16.,
+ st_theme_node_get_margin (group1, ST_SIDE_TOP));
+ /* 12px == 12px */
+ assert_length ("group1", "margin-right", 12.,
+ st_theme_node_get_margin (group1, ST_SIDE_RIGHT));
+ /* 2em == 32px (with a 12pt font) */
+ assert_length ("group1", "margin-bottom", 32.,
+ st_theme_node_get_margin (group1, ST_SIDE_BOTTOM));
+ /* 1in == 72pt == 96px, at 96dpi */
+ assert_length ("group1", "margin-left", 96.,
+ st_theme_node_get_margin (group1, ST_SIDE_LEFT));
}
static void
st_theme_node_get_padding (group2, ST_SIDE_LEFT));
}
+static void
+test_margin (void)
+{
+ test = "margin";
+ /* Test that a 4-sided margin property assigns the right margin to
+ * all sides */
+ assert_length ("group2", "margin-top", 1.,
+ st_theme_node_get_margin (group2, ST_SIDE_TOP));
+ assert_length ("group2", "margin-right", 2.,
+ st_theme_node_get_margin (group2, ST_SIDE_RIGHT));
+ assert_length ("group2", "margin-bottom", 3.,
+ st_theme_node_get_margin (group2, ST_SIDE_BOTTOM));
+ assert_length ("group2", "margin-left", 4.,
+ st_theme_node_get_margin (group2, ST_SIDE_LEFT));
+
+ /* Test that a 3-sided margin property assigns the right margin to
+ * all sides */
+ assert_length ("group4", "margin-top", 1.,
+ st_theme_node_get_margin (group4, ST_SIDE_TOP));
+ assert_length ("group4", "margin-right", 2.,
+ st_theme_node_get_margin (group4, ST_SIDE_RIGHT));
+ assert_length ("group4", "margin-bottom", 3.,
+ st_theme_node_get_margin (group4, ST_SIDE_BOTTOM));
+ assert_length ("group4", "margin-left", 2.,
+ st_theme_node_get_margin (group4, ST_SIDE_LEFT));
+
+ /* Test that a 2-sided margin property assigns the right margin to
+ * all sides */
+ assert_length ("group5", "margin-top", 1.,
+ st_theme_node_get_margin (group5, ST_SIDE_TOP));
+ assert_length ("group5", "margin-right", 2.,
+ st_theme_node_get_margin (group5, ST_SIDE_RIGHT));
+ assert_length ("group5", "margin-bottom", 1.,
+ st_theme_node_get_margin (group5, ST_SIDE_BOTTOM));
+ assert_length ("group5", "margin-left", 2.,
+ st_theme_node_get_margin (group5, ST_SIDE_LEFT));
+
+ /* Test that all sides have a margin of 0 when not specified */
+ assert_length ("group6", "margin-top", 0.,
+ st_theme_node_get_margin (group6, ST_SIDE_TOP));
+ assert_length ("group6", "margin-right", 0.,
+ st_theme_node_get_margin (group6, ST_SIDE_RIGHT));
+ assert_length ("group6", "margin-bottom", 0.,
+ st_theme_node_get_margin (group6, ST_SIDE_BOTTOM));
+ assert_length ("group6", "margin-left", 0.,
+ st_theme_node_get_margin (group6, ST_SIDE_LEFT));
+}
+
static void
test_border (void)
{
CLUTTER_TYPE_TEXT, "text2", NULL, NULL, NULL);
group2 = st_theme_node_new (context, root, NULL,
CLUTTER_TYPE_GROUP, "group2", NULL, NULL, NULL);
+ group4 = st_theme_node_new (context, root, NULL,
+ CLUTTER_TYPE_GROUP, "group4", NULL, NULL, NULL);
+ group5 = st_theme_node_new (context, root, NULL,
+ CLUTTER_TYPE_GROUP, "group5", NULL, NULL, NULL);
+ group6 = st_theme_node_new (context, root, NULL,
+ CLUTTER_TYPE_GROUP, "group6", NULL, NULL, NULL);
text3 = st_theme_node_new (context, group2, NULL,
CLUTTER_TYPE_TEXT, "text3", NULL, NULL,
"color: #0000ff; padding-bottom: 12px;");
test_type_inheritance ();
test_adjacent_selector ();
test_padding ();
+ test_margin ();
test_border ();
test_background ();
test_font ();
g_object_unref (group1);
g_object_unref (group2);
g_object_unref (group3);
+ g_object_unref (group4);
+ g_object_unref (group5);
+ g_object_unref (group6);
g_object_unref (text1);
g_object_unref (text2);
g_object_unref (text3);
padding-bottom: 2em;
padding-left: 1in;
+ margin: 12pt;
+ margin-right: 12px;
+ margin-bottom: 2em;
+ margin-left: 1in;
+
background: #ff0000 url('some-background.png');
}
#group2 {
background-image: url('other-background.png');
padding: 1px 2px 3px 4px;
+ margin: 1px 2px 3px 4px;
border: 2px solid #000000;
border-bottom: 5px solid #0000ff;
StLabel:boxed {
border: 1px;
}
+
+#group4 {
+ margin: 1px 2px 3px;
+}
+
+#group5 {
+ margin: 1px 2px;
+}
+
+#group6 {
+ padding: 5px;
+}